package util

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/bitly/go-simplejson"
	"io"
	"math/rand"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/xanzy/go-gitlab"
)

// 切片逆转
func Reverse(s []string) []string {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
	return s
}

/*获取随机整数*/
func GenerateRangeNum(min int, max int) int {
	if min == max {
		return min
	}
	rand.Seed(time.Now().Unix())
	randNum := rand.Intn(max-min) + min
	return randNum
}

func InArray(search string, targetArr []string) bool {
	for _, v := range targetArr {
		if search == v {
			return true
		}
	}
	return false
}

func InArrayForInt(search int, targetArr []int) bool {
	for _, v := range targetArr {
		if v == search {
			return true
		}
	}

	return false
}

// git文件列表转字符串切片 排除tree类型
func TreeNodesToArr(data []gitlab.TreeNode) (res []string) {
	for _, v := range data {
		if v.Type == "blob" {
			res = append(res, v.Path)
		}
	}
	return
}

// 求并集
func Union(slice1, slice2 []string) []string {
	m := make(map[string]int)
	for _, v := range slice1 {
		m[v]++
	}

	for _, v := range slice2 {
		times, _ := m[v]
		if times == 0 {
			slice1 = append(slice1, v)
		}
	}
	return slice1
}

// 求交集
func Intersect(slice1, slice2 []string) []string {
	m := make(map[string]int)
	nn := make([]string, 0)
	for _, v := range slice1 {
		m[v]++
	}

	for _, v := range slice2 {
		times, _ := m[v]
		if times == 1 {
			nn = append(nn, v)
		}
	}
	return nn
}

// 求差集 slice1-并集
func Difference(slice1, slice2 []string) []string {
	m := make(map[string]int)
	nn := make([]string, 0)
	inter := Intersect(slice1, slice2)
	for _, v := range inter {
		m[v]++
	}
	for _, value := range slice1 {
		times, _ := m[value]
		if times == 0 {
			nn = append(nn, value)
		}
	}
	return nn
}

// FormatFileSize 文件大小单位换算
func FormatFileSize(fileSize int64) (size string) {
	if fileSize < 1024 {
		return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1))
	} else if fileSize < (1024 * 1024) {
		return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024))
	} else if fileSize < (1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024))
	} else { // if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024)
		return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024))
	}
}

func TransHtmlJson(data []byte) []byte {
	data = bytes.Replace(data, []byte("\\u0026"), []byte("&"), -1)
	data = bytes.Replace(data, []byte("\\u003c"), []byte("<"), -1)
	data = bytes.Replace(data, []byte("\\u003e"), []byte(">"), -1)
	return data
}

func CopyFile(srcFileName string, dstFileName string) error {
	if err := PathExists(filepath.Dir(dstFileName)); err != nil {
		if err := os.MkdirAll(filepath.Dir(dstFileName), os.ModePerm); err != nil {
			return err
		}
	}
	//打开源文件
	srcFile, err := os.Open(srcFileName)
	if err != nil {
		return errors.New(fmt.Sprintf("源文件读取失败,原因是:%v\n", err))
	}
	defer func() {
		err = srcFile.Close()
		if err != nil {
			return
		}
	}()

	//创建目标文件,稍后会向这个目标文件写入拷贝内容
	distFile, err := os.Create(dstFileName)
	if err != nil {
		return errors.New(fmt.Sprintf("目标文件创建失败,原因是:%v\n", err))
	}
	defer func() {
		err = distFile.Close()
		if err != nil {
			return
		}
	}()
	//定义指定长度的字节切片,每次最多读取指定长度
	var tmp = make([]byte, 1024*4)
	//循环读取并写入
	for {
		n, err := srcFile.Read(tmp)
		n, _ = distFile.Write(tmp[:n])
		if err != nil {
			if err == io.EOF { //读到了文件末尾,并且写入完毕,任务完成返回(关闭文件的操作由defer来完成)
				return nil
			} else {
				return errors.New(fmt.Sprintf("拷贝过程中发生错误,错误原因为:%v\n", err))
			}
		}
	}
}

//追加写入文件
func Tracefile(name, content string) error {
	if err := PathExists(filepath.Dir(name)); err != nil {
		if err := os.MkdirAll(filepath.Dir(name), os.ModePerm); err != nil {
			return err
		}
	}
	fd, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		return err
	}
	buf := []byte(content)
	defer fd.Close()
	_, err = fd.Write(buf)
	return err

}

// remove duplicates 去重
func RmDup(arr []int) []int {
	result := make([]int, 0)
	for _, v := range arr {
		if !InArrayForInt(v, result) {
			result = append(result, v)
		}
	}
	return result
}

// List[1] 数组表达式判断
func IsArrayExp(str string) (field string, index int, yes bool) {
	var rgx = regexp.MustCompile(`\[(0|\+?[1-9][0-9]*)\]`) // 匹配第一个 [] 内容,括号内 确保为 非负整数
	rs := rgx.FindStringSubmatch(str)                      // rs[0]: [ ** ]; rs[1]: ***
	if len(rs) == 2 {
		field = strings.Replace(str, rs[0], "", -1)
		index, _ = strconv.Atoi(rs[1])
		yes = true
		if field == "" || index < 0 {
			yes = false
		}
	}
	return
}

// 根据 数组表达式从Json数据中 获取 下一层Json数据
func NextJsonByArrayExp(Js *simplejson.Json, field string, index int) (*simplejson.Json, error) {
	result := simplejson.New()

	temp := Js.Get(field)
	if temp != nil {
		d, err := temp.Array()
		if err != nil {
			return result, err
		}
		if len(d) < index+1 {
			return result, errors.New("index out of array")
		}
		bytes, err := json.Marshal(d[index])
		if err != nil {
			return result, err
		}
		J, err := simplejson.NewJson(bytes)
		if err != nil {
			return result, err
		}
		result = J
	}
	return result, nil
}

//hmac_sha256加密
func ComputeHmacSha256(message string, secret string) string {
	key := []byte(secret)
	h := hmac.New(sha256.New, key)
	h.Write([]byte(message))
	//	fmt.Println(h.Sum(nil))
	sha := hex.EncodeToString(h.Sum(nil))
	//	fmt.Println(sha)

	//	hex.EncodeToString(h.Sum(nil))
	return base64.StdEncoding.EncodeToString([]byte(sha))
}
